Исходя из того, что проблема восстановления данных являлась всегда насущной, решил создать эту тему. Скажу сразу, что описанные здесь методы можно применить тогда, когда разрушения носят логический характер. Попытки "самолечения" в девяти из десяти случаев заканчиваются полным провалом и необратимым уничтожением тех данных, которые еще можно было спасти. Тем не менее, обращение к специалистам далеко не всегда оправдано, особенно если речь идет о секретной информации. В некоторых случаях данные можно восстановить и самостоятельно.
Пытаясь "отремонтировать" данные самостоятельно вы идете на огромный риск, особенно если доверяете это дело различными утилитам, слепо веря в их интеллектуальность. С другой стороны, многие "специалисты" используют те же самые утилиты, поэтому отдавать винчестер им на растерзание, по меньшей мере неразумно. К потерянным данным добавятся еще и потерянные деньги, поэтому попробуем разобраться в этом деле сами.
Для начала позвольте дать Вам несколько советов:
1) Никогда не записывайте на восстанавливаемый диск, и уже тем более не запускайте chkdsk и дефрагментатор!
2) Не пытайтесь читать bad-сектора больше двух раз!
3) Занимайтесь восстановлением только в трезвом уме и здравой памяти, переждав, пока шоковое состояния от пережитого пройдет!
Когда винчестеры с NTFS на борту бороздят дисковое пространство, говорить об остальных файловых системах (типа FAT16/32) становится просто неэтично (о покойниках плохо не говорят), поэтому сосредоточим свое внимание исключительно на NTFS.
Знакомство с файловой системой NTFS
Несмотря на существующие различия в структуре раздела файловых систем FAT и NTFS, они имеют подобные элементы, например загрузочную область. Раздел NTFS состоит из главной таблицы файлов MFT. Однако MFT — это не то же самое, что FAT. Вместо использования таблицы со ссылками на кластеры, MFT содержит больше информации о файлах и каталогах в разделе. В некоторых случаях MFT может даже содержать файлы и каталоги.
Существует несколько факторов, которые определяют степень сложности процесса восстановления данных, в том числе:
- способ удаления данных
- файловая система накопителя
- форма хранения данных (оптические, магнитные носители, флэш-память и т.д)
- используемая версия Windows
- наличие программного обеспечения по защите данных
- наличие физических повреждений.
Наша задача - вернуть разрушенный том в рабочее состояние (задача максимум) или извлечь из него все ценные файлы (задача минимум). Реально нам потребуется разобраться лишь с устройством главной файловой записи - MFT и нескольких дочерних подструктур.
При организации раздела NTFS создает 10 системных файлов:
$mft - Содержит запись для каждого файла в разделе
$mftmirr - Зеркальная копия MFT, используемая для восстановления
$badclus - Содержит все повреждённые сектора раздела
$bitmap - Содержит карту распределения занятых кластеров
$boot - Содержит загрузочную информацию (если раздел загрузочный)
$attrdef - Таблица определения атрибутов
$logfile - Журнал транзакаций, используемый для восстановления
$quota - Таблица квот пользователей
$upcase - Таблица символов
$volume - Информация о разделе (имя, версия)
$extend - Файл расширения (квоты, идентификаторы, параметры точек монтирования)
Без имени - Индекс корневого каталога |
Самым главным служебным файлом является $MFT (Master File Table) - своеобразная база данных, хранящая информацию обо всех файлах тома, их именах, атрибутах, порядке размещения на диске. Каталог также является файлом особого типа со списком принадлежащих ему файлов и подкаталогов внутри.
Важно!!! В MFT присутствуют все файлы, находящиеся во всех подкаталогах тома, поэтому для восстановления диска наличия $MTF-файла будет вполне достаточно. Остальные служебные файлы (со знаком '$') носят вспомогательный характер и интересны только самой файловой системе.
Всякий NTFS-файл представляет собой совокупность атрибутов, каждый из которых хранится как отдельный поток байтов, поэтому во избежание путаницы атрибуты, хранящие данные файла, часто называют потоками. Каждый атрибут состоит из тела (body) и заголовка (header). Атрибуты делятся на резидентные (resident) и нерезидентные (non-resident). Резидентные атрибуты хранятся непосредственно в $MTF, нерезидентные хранят в $MTF лишь свой заголовок, описывающий порядок размещения атрибута на диске. Назначение атрибута определяется его типом (type) - четырехбайтовым шестнадцатеричным значением.
Большинство файлов имеет по 3 атрибута:
- Cтандартная инфа о файле (время создания и т.д.) хранится в атрибуте типа 10h ($STANDARD_INFORMATION).
- Имя файла хранится в атрибуте типа 30h ($FILE_NAME).
- Данные файла по умолчанию хранятся в безымянном атрибуте типа 80h ($DATA).
Как уже говорилось, каталог представляет собой особенный файл - файл индексов (INDEX).
Главная файловая запись $MFT
В процессе форматирования в начале раздела создаётся MTF-зона, по умолчанию занимающая 12% от ёмкости тома. В этой области расположен $MFT-файл, изначально занимающий порядка 64 секторов и растущий от начала MFT-зоны к ее концу, по мере создания новых файлов. Таким образом, чем больше файлов содержаться на дисковом томе, тем больше размер MTF.
При необходимости, $MFT-файл может быть перемещен в любую часть диска. Стартовый адрес $MFT-файла хранится в Boot-секторе по смещению 30h байт от его начала, и в большинстве случаев этот адрес ссылается на 4-й кластер.
$MFT-файл представляет собой массив записей типа "FILE Record", каждая из которых описывает соответствующий ей файл или подкаталог. В большинстве случаев один файл полностью описывается одной записью "FILE Record". Для ссылки на одну файловую запись из другой, используется её порядковый номер (индекс). Файловая ссылка состоит из двух частей - индекса и номера последовательности.
При удалении файла соответствующая ему файловая последовательность помечается как неиспользуемая. При создании новых файлов эти последовательности могут задействоваться вновь, при этом счетчик (внутри файловой записи) увеличивается на единицу. Этот механизм позволяет отслеживать "мертвые" ссылки на уже удаленные файлы.
Первые 12 записей в MFT всегда занимают служебные метафайлы: $MFT, $MFTMirr, $Volume и т.д. Первые четыре записи настолько важны, что продублированы в специальном $MFTMirr-файле, находящимся приблизительно посередине диска. Точное расположение $MFTmirr-файла хранится в boot-секторе, по смещению 38h байт от его начала. Вопреки своему названию, $MFTmirr это отнюдь не зеркало всего $MFT-файла, это всего лишь копия первых четырех элементов.
Записи с 12 по 15 помечены как используемые, но в действительности-же они пусты. Эт запас на будущее. Записи с 16 по 23 не задействованы и забиты нулями. Начиная с 24-ой записи, располагаются пользовательские файлы и каталоги.
Для знакомства с MFT запустим WinHex и нажмём клавишу F9 (EditDisk), выбираем [Logical Drives C:\] и жмём ОК:
Файловая запись (FILE Record) состоит из заголовка и нескольких атрибутов, которые завершаются маркером конца (FF FF FF FFh). Несмотря на то, что количество и длина атрибутов НЕпостоянна, размер самой "FILE Record" строго фиксирован и равен 1 Кбайту, причем первый байт записи всегда совпадает с началом сектора.
Первые четыре байта заголовка (46 49 4С 45) оккупированы магической последовательностью "FILE*", сигнализирующей о том, что мы имеем дело с файловой записью типа "FILE Record". При восстановлении фрагментированного $MFT файла это обстоятельство играет решающую роль, поскольку позволяет отличить сектора, принадлежащие MFT, от всех остальных.
Следом за сигнатурой "FILE*" идет указатель, который содержит адрес смещения, где находится последовательность обновлений. В XP и старше последовательность обновлений хранится по смещению 002Dh от начала дампа.
Размер файловой записи хранится в двух полях; в поле реального размера, находящееся по смещению 18h байт от начала сектора, и в поле выделенного размера находящееся по смещению 1Сh. Реальный размер файловой записи в байтах, округляется по размеру сектора, т.е. если размер записи 3.8Кбайт, то указывается 4.
Поле флагов, находящееся по смещению 16h байт от начала сектора, обычно принимает одно из следующих значений:
00h - данная файловая запись не используется или файл/каталог удален
01h - файловая запись используется и описывает файл
02h - файловая запись используется и описывает каталог
Поле, находящееся по смещению 20h байт от начала сектора, содержит индекс файловой записи. Для первой файловой записи это поле всегда равно нулю, а для всех последующих записей - индексу первой файловой записи. Остальные поля заголовка файловой записи не столь важны и поэтому здесь не рассматриваются.
Теперь разберёмся с размерами... Для каждого файла на диске, ХР в любом случае выделяет 1 кластер (4Кбайт). Убедиться в этом можно следующем образом. Зайдите в свойства любого маленького файла (к примеру ярлыка), там два значения: первое - реальный размер файла, второе - размер на диске (по умолчанию - 4К). Размер на диске соответствует размеру кластера! Если файл больше размера кластера, то он занимает следующие кластера.
Кластер - это в ХР восемь секторов (сектор=512 байт; 512*8=4096 или 4 Кбайт). Раздел C:\ на моём носителе имеет размер 20Gb или 20971520 Кбайт. Разделив это значение на 4 Кб (один кластер), мы получим общее количество кластеров в разделе (5 242 880).
Последовательности обновления
Будучи важными компонентами файловой системы, $MFT, INDEX и $LogFile нуждаются в механизме контроля целостности своего содержимого. Для этого, в конец каждого из секторов слагающих файловую запись, записывается специальный номер обновления. При каждой операции чтения два последних байта сектора сверяются с полем заголовка, и если NTFS-драйвер обнаружит расхождение - данная файловая запись считается недействительной!
Содержимое файла хранится в специальном массиве, расположенном в заголовке файловой записи. Для восстановления файловой записи мы должны извлечь из заголовка указатель (он хранится по смещению 04h байт от начала заголовка) и сверить его с двумя последними байтами каждого из секторов, слагающих файловую запись. Если они НЕ совпадут, значит соответствующая структура данных повреждена!
По смещению 06h от начала сектора находится поле (2 байта), хранящее совокупный размер номера обновления и массива последовательности. В XP он располагается по смещениям 2Dh и 2Fh соответственно.
Первые два байта массива обновления, соответствуют последним двум байтам первого сектора "FILE Record". Два последних байта первого сектора, соответствуют двум последним байтам второго сектора, и т.д. Для восстановления сектора в исходный вид мы должны вернуть все элементы массива обновления на их законные места (советую модифицировать не сам сектор, а его копию).
Продемонстрируем это на следующем примере (значимые смещения выделены цветом):
Ссылка на указатель
Указатель значения обновлений
Обновления
---> Первый сектор $MFT. (FILE Record)
0С000000 46 49 4C 45 30 00 03 00 - 90 8D 5B 26 00 00 00 00 FILE*...........
0С000010 01 00 01 00 38 00 01 00 - A0 01 00 00 00 04 00 00 ................
0С000020 00 00 00 00 00 00 00 00 - 06 00 00 00 00 00 00 00 ................
0С000030 9D 02 00 00 00 00 00 00 - 10 00 00 00 60 00 00 00 ................
...
0С0001F0 31 01 FF FF 0B 00 00 00 - FF FF FF FF 00 00 9D 02 ................
---> Конец первого сектора файла
...
0С0003F0 00 00 B3 AF 00 00 00 00 - 00 00 4D 00 01 00 9D 02 ................
---> Конец второго сектора файла
Сигнатура "FILE" указывает на начало файловой записи. А раз так, то по смещению 04h байт будет расположен 2-хбайтный указатель на номер последовательности обновления. В данном случае он равен 30 00h.
т.к. 30 00h это уже "слово" (размер 2 байта), меняем байты местами и получаем 00 30h. Ок, переходим по смещению 0х0030h и видим, что здесь лежит слово 9D 02h. Перемещаемся в конец сектора и сверяем его с последними двумя байтами. Как и предполагалось, они совпадают. Повторяем ту же самую операцию со следующим сектором.
Обычно файловая запись занимает два сектора (1 Кб), но в некотых случаях она может выходить за рамки двух секторов. Чтобы не гадать, необходимо извлечь двухбайтное значение со смещения 06h от начала записи (в данном случае 00 03h, в виде переставленных байтов), и вычесть от него единицу. Действительно, получается два (сектора).
Теперь, необходимо найти массив последовательности обновлений, хранящий оригинальное значение последнего слова каждого из секторов. Смещение массива - равно значению указателя, плюс два (в данном случае 0030h + 02h = 0032h). Извлекаем первое слово с этого смещения (в данном случае равное 00 00h) и записываем его в конец первого сектора. Извлекаем следующее слово (00 00h) и записываем его в конец второго сектора.
В результате восстановленный сектор будет выглядеть так:
---> Первый сектор $MFT. (FILE Record)
0С000000 46 49 4C 45 30 00 03 00 - 90 8D 5B 26 00 00 00 00 FILE*...........
0С000010 01 00 01 00 38 00 01 00 - A0 01 00 00 00 04 00 00 ................
0С000020 00 00 00 00 00 00 00 00 - 06 00 00 00 00 00 00 00 ................
0С000030 9D 02 00 00 00 00 00 00 - 10 00 00 00 60 00 00 00 ................
...
0С0001F0 31 01 FF FF 0B 00 00 00 - FF FF FF FF 00 00 00 00 ................
---> Конец первого сектора файла
...
0С0003F0 00 00 B3 AF 00 00 00 00 - 00 00 4D 00 01 00 00 00 ................
---> Конец второго сектора файла
Внимание!!! FILE Record, INDEX Record искажены последовательностями обновлений и в обязательном порядке должны быть восстановлены! В противном случае, вместо актуальных данных вы получите мусор.
Коротко о главном
Рассмотрим на практике технику разбора файловой записи. Воспользовавшись любым дисковым редактором (WinHex, Disk Probe) попробуем декодировать одну файловую запись вручную. Найдем сектор, содержащий сигнатуру "FILE" в его начале, который у меня выглядит так (разные атрибуты выделены разным цветом):
0C0000000 46 49 4C 45 30 00 03 00 - 57 5D 5F 2C 00 00 00 00 FILE0...W]_,....
0C0000010 01 00 01 00 38 00 01 00 - A0 01 00 00 00 04 00 00 ....8... .......
0C0000020 00 00 00 00 00 00 00 00 - 06 00 00 00 00 00 00 00 ................
0C0000030 14 03 00 00 00 00 00 00 - 10 00 00 00 60 00 00 00 ............`...
0C0000040 00 00 18 00 00 00 00 00 - 48 00 00 00 18 00 00 00 ........H.......
0C0000050 FE 84 0E CB 87 D5 CB 01 - FE 84 0E CB 87 D5 CB 01 ю„.Л‡ХЛ.ю„.Л‡ХЛ.
0C0000060 FE 84 0E CB 87 D5 CB 01 - FE 84 0E CB 87 D5 CB 01 ю„.Л‡ХЛ.ю„.Л‡ХЛ.
0C0000070 06 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
0C0000080 00 00 00 00 00 01 00 00 - 00 00 00 00 00 00 00 00 ................
0C0000090 00 00 00 00 00 00 00 00 - 30 00 00 00 68 00 00 00 ........0...h...
0C00000A0 00 00 18 00 00 00 03 00 - 4A 00 00 00 18 00 01 00 ........J.......
0C00000B0 05 00 00 00 00 00 05 00 - FE 84 0E CB 87 D5 CB 01 ........ю„.Л‡ХЛ.
0C00000C0 FE 84 0E CB 87 D5 CB 01 - FE 84 0E CB 87 D5 CB 01 ю„.Л‡ХЛ.ю„.Л‡ХЛ.
0C00000D0 FE 84 0E CB 87 D5 CB 01 - 00 40 00 00 00 00 00 00 ю„.Л‡ХЛ..@......
0C00000E0 00 40 00 00 00 00 00 00 - 06 00 00 00 00 00 00 00 .@..............
0C00000F0 04 03 24 00 4D 00 46 00 - 54 00 00 00 00 00 00 00 ..$.M.F.T.......
0C0000100 80 00 00 00 48 00 00 00 - 01 00 40 00 00 00 01 00 Ђ...H.....@.....
0C0000110 00 00 00 00 00 00 00 00 - 17 45 00 00 00 00 00 00 .........E......
0C0000120 40 00 00 00 00 00 00 00 - 00 80 51 04 00 00 00 00 @........ЂQ.....
0C0000130 00 80 51 04 00 00 00 00 - 00 80 51 04 00 00 00 00 .ЂQ......ЂQ.....
0C0000140 32 18 45 00 00 0C 00 00 - B0 00 00 00 50 00 00 00 2.E.....°...P...
0C0000150 01 00 40 00 00 00 05 00 - 00 00 00 00 00 00 00 00 ..@.............
0C0000160 02 00 00 00 00 00 00 00 - 40 00 00 00 00 00 00 00 ........@.......
0C0000170 00 30 00 00 00 00 00 00 - 90 22 00 00 00 00 00 00 .0......ђ"......
0C0000180 90 22 00 00 00 00 00 00 - 31 01 FF FF 0B 31 01 B4 ђ"......1.яя.1.ґ
0C0000190 E5 11 31 01 07 65 E6 00 - FF FF FF FF 00 00 00 00 е.1..eж.яяяя....
0C00001A0 00 80 00 00 00 00 00 00 - 31 08 00 00 0C 00 01 00 .Ђ......1.......
0C00001B0 B0 00 00 00 48 00 00 00 - 01 00 40 00 00 00 05 00 °...H.....@.....
0C00001C0 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
0C00001D0 40 00 00 00 00 00 00 00 - 00 10 00 00 00 00 00 00 @...............
0C00001E0 08 00 00 00 00 00 00 00 - 08 00 00 00 00 00 00 00 ................
0C00001F0 31 01 FF FF 0B 00 00 00 - FF FF FF FF 00 00 14 03 1.яя....яяяя....
1) Первым делом необходимо восстановить оригинальное содержимое последовательности обновления. По смещению 04h от начала сектора лежит 2-хбайтный (две пары цифр) указатель на неё, равный в данном случае 30 00h (значит, это NTFS 3.0 или выше). А что у нас лежит по смещению 30h? Ага, пара байт 14 03h. Это - номер последовательности обновления. Сверяем его с содержимым двух последних байт этого и следующего секторов (смещения 1FEh и 3FEh соответственно). Они равны! Значит, данная файловая запись цела и можно переходить к операции спасения.
2) По смещению 2Ch расположен массив, содержащий оригинальные значения последовательности обновления. Количество элементов в нём равно содержимому 2-хбайтного поля, расположенному по смещению 06h от начала сектора и уменьшенного на единицу (в данном случае 03h - 01h = 02h). Извлекаем 4 байта начиная со смещения 2Ch (в данном случае они равны 00 00 и 00 00), и записываем их в конец первого и последнего секторов.
3) Теперь нам необходимо выяснить - используется ли данная файловая запись, или ассоциированный с ней файл был удалён! 2-хбайтное поле по смещению 16h содержит значение 01 00h, следовательно перед нами файл, а не каталог и этот файл ещё не удален (00h-удалён). Но является ли данная файловая запись базовой для данного файла, или мы имеет дело с ее продолжением? 8-мибайтное поле расположенное по смещению 20h равно нулю, следовательно данная файловая запись - базовая!
4) ОК, переходим к исследованию атрибутов... 2-хбайтное поле находящееся по смещению 14h равно 38 00h, следовательно заголовок атрибута начинается со смещения 38h от начала сектора.
Первые 4 байта первого атрибута (выделен синим) равны 10h, значит перед нами атрибут типа $STANDARD_INFORMATION (см. таблицу ниже). Следующие 4-байта атрибута (смещение 3Ch) равны в данном случае 60h. Это позволяет нам вычислить смещение следующего атрибута в списке:
38h (смещение 1-го атрибута) + 60h (его длина) = 98h (смещение следующего атрибута)
Первые 4 байта второго атрибута равны 30h, значит это атрибут типа $NAME и следующие 4 байта хранят его длину (в данном случае 68h). Сложив длину атрибута с его смещением, мы получим смещение следующего атрибута:
98h + 68h = 100h
Первые 4 байта третьего атрибута равны 80h, следовательно это атрибут типа $DATA, хранящий (!)основные данные файла. Складываем смешение с длиной - 100h + 48h = 148h (смещение следующего атрибута).
Первые 4 байта червёртого атрибута равны B0h - это $BITMAP (карта свободного пространства). Также, складываем его смещение с длинной
148h + 50h = 198h.
Упс! Мы наткнулись на частокол FF FF FF FFh сигнализирующий о том, что атрибут $BITMAP - последний в списке!!!
Типы атрибутов:
010h - $STANDARD_INFORMATION
020h - $ATTRIBUTE_LIST
030h - $FILE_NAME
040h - $VOLUME_VERSION
050h - $SECURITY_DESCRIPTOR
060h - $VOLUME_NAME
070h - $VOLUME_INFORMATION
080h - $DATA (основные данные файла)
090h - $INDEX_ROOT (корень индексов)
0A0h - $INDEX_ALLOCATION (ветви индекса)
0B0h - $BITMAP (карта свободного пространства)
0C0h - $SYMBOLIC_LINK (символическая связь)
0D0h - $EA_INFORMATION (атрибуты для HPFS)
0E0h - $EA (расширенные атрибуты для HPFS)
100h - $LOGGED_UTILITY_STREAM (используется EFS)
Разделываем тушу...
Разбив файловую запись на атрибуты (как мясник тушу), приступим к исследованию каждого из атрибутов в отдельности. Начнём с имени..
- Байт, находящееся по смещению 08h от начала атрибутного заголовка (смещение A0h от начала сектора), содержит флаг неризидентности, который в данном случае равен нулю (т.е. атрибут резидентный и его тело хранится в самой файловой записи, что есть гуд).
- 2 байта по смещению 0Ch от начала заголовка (A4h от начала сектора) равны нулю, следовательно тело атрибута не сжато и не зашифровано.
- 4 байта по смещению 10h от начала заголовка (A8h от начала сектора), содержит длину атрибутного тела, равную в данном случае 4Ah байт, а 2 байта по смещению 14h от начала заголовка (AСh от начала сектора), хранит смещение атрибутного тела, равное в данном случае 18h. Следовательно тело атрибута $NAME располагается по смещению B0h от начала сектора.
- Длина имени восстанавливаемого файла содержится в байте по смещению 40h от начала тела атрибута $NAME (F0h от начала сектора). В данном случае оно равно 04h. Само-же имя начинается со смещения 42h от начала тела $NAME (F2h от сектора). Как видим, здесь находится файл-$MFT... (я неудачно выбрал подопытный кластер (первый попавшийся), поэтому поймал файл-MFT, а ни какой-нибудь другой. Но это сути не меняет! Попробуйте выбрать другой кластер - попадётся другой файл...) Ну да ладно, ..переходим к атрибуту основных данных файла.
- Реальная длина тела атрибута (в байтах), содержится в 8-ми байтом поле, расположенном по смещению 30h от начала заголовка (130h от начала сектора). В данном случае она равна:
00 80 51 04 00 00 00 00h Переставляем справа-налево соседние байты местами и получаем: 04518000h или 72.450.048 байт (69Мb)
Как говорилось выше, файл - это набор атрибутов и здесь реальная длинна атрибута соответствует реальному размеру файла (~69 Mb). Остается лишь декодировать список отрезков, адрес которого хранится в 2-х байтах по смещению 20h от начала заголовка (120h от начала сектора). В данном случае оно равно 40h, что соответствует смещению от начала сектора в 140h.
Сам же список отрезков выглядит так: 32 18 45 00 00 0C 00 00. Ага! Пропускаем первый байт (32h), а два последующих байта занимает поле длины (4518h кластеров). Три следующих байта указывают на начальный кластер (0С0000h). Два байта нулей в конце сигнализируют о том, что этот отрезок последний в списке.
Подытожим полученную информацию.
1) Файл называется $MFT, он начинается с кластера 0C0000h (786.432)
2) ..и продолжается вплоть до кластера 4518h + 0C0000h = 0C4518h (804.120)
3) ..при реальном размере файла 72.450.048 байт.
Теперь уже ничего не стоит скопировать файл на резервный носитель!
Так что, восстанавливать данные с носителей можно и вручную, вооружившись всего одним дисковым редактором и виндозным калькулятором! За сим - всё!!! Чё не ясно - пишите...
P.S.\\ Кстати, редактор диска Disk Probe валяется на загрузочном диске, в папке SUPPORT-CD\TOOLS\SUPPORT.CAB...
|